﻿using System;
using System.Collections.Generic;
using System.Text;
using OpenFrameworkCore.Controls;
using System.Windows.Controls;
using System.Windows;
using OpenFrameworkWriter.Controls;
using System.Collections.ObjectModel;
using System.Windows.Shapes;
using System.Windows.Input;
using System.Windows.Media;
using System.Linq;

namespace OpenFrameworkWriter
{
	[TemplatePart(Name = AreaSelectControlName, Type = typeof(AreaSelectControl))]
	public abstract class ControlEditContainerBase : ControlContainerBase
	{
		// Editor와 관련된 ZIndex
		private const int EDITOR_MIN_ZINDEX = 1001;
		private const int EDITOR_MAX_ZINDEX = 2000;

		private const string AreaSelectControlName = "AreaSelect";
		protected AreaSelectControl AreaSelect;

		/// <summary>
		/// ControlContextToEditorMapper is mapping ControlBaseContext and EditorBase.
		/// </summary>
		protected IDictionary<ControlBaseContext, EditorBase> ControlContextToEditorMapper;

		#region SelectedEditors
		/// <summary>
		/// 선택된 Editor들
		/// </summary>
		private IList<EditorBase> selectedEditors;
		public IList<EditorBase> SelectedEditors
		{
			get
			{
				return selectedEditors;
			}

			private set
			{
				selectedEditors = value;
			}
		}
		#endregion

		/// <summary>
		/// ControlEditContainer에서 사용할 Editor Class Type
		/// </summary>
		protected abstract Type EditorType { get; }

		/// <summary>
		/// 생성자
		/// </summary>
		public ControlEditContainerBase()
		{
			ControlContextToEditorMapper = new Dictionary<ControlBaseContext, EditorBase>();
			SelectedEditors = new List<EditorBase>();
		}

		/// <summary>
		/// Template 적용시 필요한 엘리먼트를 찾습니다.
		/// </summary>
		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();

			AreaSelect = (AreaSelectControl)GetTemplateChild(AreaSelectControlName);
			if (AreaSelect == null)
				throw new TemplatePartNotFoundException("AreaSelect를 찾을 수 없습니다.");

			// 영역이 선택된 경우 발생하는 이벤트의 핸들러
			AreaSelect.AreaSelected += delegate(object sender, AreaSelectControlEventArgs e)
			{
				Rect selectedRect = new Rect(e.BeginPoint, e.EndPoint);

				// 마우스가 선택된 지역의 Editor를 찾습니다.
				var selectedEditorVar = (from item in VisualTreeHelper.FindElementsInHostCoordinates(selectedRect, this)
										 where item is EditorBase
										 orderby ((EditorBase)item).TargetControl.GetValue(Canvas.ZIndexProperty) descending
										 select item);

				System.Diagnostics.Debug.WriteLine
					(
					"X: " + selectedRect.X + " Y: " + selectedRect.Y + " Width: " + selectedRect.Width + " Height: " + selectedRect.Height
					);
				System.Diagnostics.Debug.WriteLine
					(
					"Selected Editor: " + selectedEditorVar.Count()
					);

				// 선택된 Editor가 없으면 종료
				if (selectedEditorVar.Count() == 0)
					// 기존에 선택되었던 Editor를 모두 UnSelected로 변경
					foreach (EditorBase selectedEditor in SelectedEditors.ToList())
						selectedEditor.State = EditorState.UnSelected;

				// 선택된 Editor가 존재하는 경우
				else
				{
					if (e.SelectType == SelectType.Point)
					{
						System.Diagnostics.Debug.WriteLine("Point");

						EditorBase selectedEditor = (EditorBase)selectedEditorVar.First();
						selectedEditor.State = EditorState.Selected;
					}
					else if(e.SelectType == SelectType.Area)
					{
						System.Diagnostics.Debug.WriteLine("Area");

						foreach (EditorBase selectedEditor in selectedEditorVar)
							if (SelectedEditors.Contains(selectedEditor) == false)
								selectedEditor.State = EditorState.Selected;
					}
				}
			};

			// 마우스 왼쪽 버튼이 눌린 경우 Area 선택 시작
			RootElement.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e)
			{
				if (e.Handled)
					return;

				e.Handled = true;

				// 선택된 Editor 제거
				// 기존에 선택되었던 Editor를 모두 UnSelected로 변경
				foreach (EditorBase selectedEditor in SelectedEditors.ToList())
					selectedEditor.State = EditorState.UnSelected;

				// Area 선택 시작
				AreaSelect.BeginAreaSelecting(e.GetPosition(AreaSelect));
			};

			// 마우스 오른쪽 버튼이 눌린 경우 Area 선택 마침
			RootElement.MouseLeftButtonUp += delegate(object sender, MouseButtonEventArgs e)
			{
				if (e.Handled)
					return;

				e.Handled = true;

				// Area 선택 시작
				AreaSelect.EndAreaSelecting();
			};
		}

		/// <summary>
		/// Control이 추가될때 호출되는 메서드
		/// 여기서는 Control이 추가되면 Editor를 같이 추가해주는 행동을 한다.
		/// </summary>
		/// <param name="targetControl"></param>
		protected override void OnControlAdded(ControlBase addedControl)
		{
			base.OnControlAdded(addedControl);

			// 새로운 Control에 최상위 ZIndex 부여
			if (addedControl.ZIndex == 0)
			{
				int maxZIndex = 0;

				foreach (ControlBaseContext basicControlContext in ControlContextToEditorMapper.Keys)
					if (maxZIndex < basicControlContext.ZIndex)
						maxZIndex = basicControlContext.ZIndex;

				addedControl.ZIndex = maxZIndex + 1;
			}

			// Editor 생성
			EditorBase editor = (EditorBase)Activator.CreateInstance(EditorType, new object[] { this });
			editor.TargetControl = addedControl;
			editor.State = EditorState.UnSelected;

			// Editor의 ZIndex 설정
			editor.SetValue(Canvas.ZIndexProperty, EDITOR_MIN_ZINDEX);

			editor.StateChanged += delegate(object sender, StateChangedEventArgs e)
			{
				if (e.ChangedState == EditorState.Selected)
				{
					SelectedEditors.Add(editor);

					editor.SetValue(Canvas.ZIndexProperty, EDITOR_MIN_ZINDEX + SelectedEditors.Count);
				}
				else if (e.ChangedState == EditorState.UnSelected)
				{
					SelectedEditors.Remove(editor);

					editor.SetValue(Canvas.ZIndexProperty, EDITOR_MIN_ZINDEX);
				}
			};

            // Mapper에 추가
            ControlContextToEditorMapper.Add(addedControl.ControlContext, editor);

			// Editor 추가
			ControlHost.Children.Add(editor);
        }
	}
}
